package main

import (
	"flag"
	"fmt"
	"kratos-layout/pkg/logger"
	"os"
	"os/signal"
	"runtime"
	"syscall"

	"kratos-layout/internal/conf"

	"github.com/go-kratos/kratos/v2"
	"github.com/go-kratos/kratos/v2/config"
	"github.com/go-kratos/kratos/v2/config/file"
	"github.com/go-kratos/kratos/v2/log"
	"github.com/go-kratos/kratos/v2/transport/grpc"
	"github.com/go-kratos/kratos/v2/transport/http"
)

// go build -ldflags "-X main.Version=x.y.z"
var (
	// Name is the name of the compiled software.
	Name string
	// Version is the version of the compiled software.
	Version string
	// flagconf is the config flag.
	flagconf    string
	showVersion bool
	BuildDate   string
	GitCommit   string

	id, _ = os.Hostname()
)

func init() {
	flag.StringVar(&flagconf, "conf", "configs/config.yaml", "config path, eg: -conf config.yaml")
	flag.BoolVar(&showVersion, "v", false, "show version")
}

func newApp(logger log.Logger, hs *http.Server, gs *grpc.Server) *kratos.App {
	return kratos.New(
		kratos.ID(id),
		kratos.Name(Name),
		kratos.Version(Version),
		kratos.Metadata(map[string]string{}),
		kratos.Logger(logger),
		kratos.Server(
			hs,
			gs,
		),
	)
}

func WaitUntilCtrlC() {
	stopCh := make(chan os.Signal, 1)
	signal.Notify(stopCh, syscall.SIGINT, syscall.SIGTERM)

	go func() {
		sig := <-stopCh
		fmt.Printf("Received signal %v, exiting...\n", sig)
		os.Exit(0)
	}()

	select {}
}

func main() {
	flag.Parse()
	if err := logger.InitGlobalLogger(logger.Configuration{
		EnableConsole: true,
		ConsoleLevel:  "info",
		EnableFile:    true,
		FileLevel:     "info",
		FileLocation:  "kratos-layout.log",
	}, 0); err != nil {
		panic(err.Error())
	}

	if showVersion {
		fmt.Printf("    kratos-layout kratos Version: %s\r\n", Version)
		fmt.Printf("    kratos-layout GoVersion: %s %s/%s\n", runtime.Version(), runtime.GOOS, runtime.GOARCH)
		fmt.Printf("    kratos-layout GitCommit: %s\r\n", GitCommit)
		fmt.Printf("    kratos-layout BuildDate: %s\r\n", BuildDate)
		os.Exit(0)
	}

	c := config.New(
		config.WithSource(
			file.NewSource(flagconf),
		),
	)
	defer c.Close()

	if err := c.Load(); err != nil {
		panic(err)
	}

	var bc conf.Bootstrap
	if err := c.Scan(&bc); err != nil {
		panic(err)
	}

	if bc.App.LogLevel != "info" {
		logger.SetLogLevel(bc.App.LogLevel)
	}
	// 监控日志级别配置变更
	c.Watch("app.log_level", func(k string, v config.Value) {
		var level string
		if err := v.Scan(&level); err == nil {
			logger.SetLogLevel(level)
		}
		return
	})

	if bc.Server.Http.Addr == "" && bc.Server.Grpc.Addr == "" {
		WaitUntilCtrlC()
	} else {
		app, cleanup, err := initApp(bc.Server, bc.Data, nil)
		if err != nil {
			panic(err)
		}
		defer cleanup()

		// start and wait for stop signal
		if err := app.Run(); err != nil {
			panic(err)
		}
	}
}
